/**
 @file        Infrasound.VDM.History.c
 @ingroup     libVDM						
 @brief       history for network data segments
 @version     $0.1$					
 @since       1.0
 @author      Andreas Schlueter

 

 $Id$
 */

#include <Infrasound.VDM.History.h>
#include "Infrasound.VDM.internals.h"

volatile history_entry_t	history[HISTORY_SIZE];	///< the history
extern sd_block_t		vdm_buffer[];		///< data RAM


/**
 * @brief marks all entries as overwritable
 */
void history_init(){
	uint16_t i;
	uint16_t up = HISTORY_SIZE<<1;
	for(i=0; i<up; i++){
		*(((uint16_t*)history) + i) = 0xFFFF;
	}
}

/**
 * @brief confirms history entry
 *        note: the according segment in RAM will be removed
 *
 * @return status after operation
 */
enum segment_status history_confirm(segment_key_t id){
	history_entry_t* e= (history_entry_t*)&(history[HASH(id)]);

	//update or overwrite paged or overwrite confirmed segment
	if(e->id.raw == id.raw || e->info.properties.paged || e->info.properties.confirmed){
#ifdef VDM_DEBUG
		if(e->info.properties.confirmed)
			printf("(WARN)history_confirm: segment %u already confirmed\n", id.raw);
#endif
		e->id.raw = id.raw;
		e->info.properties.confirmed  = true;

		//remove form ram (if not paged, of course)
		if(!(e->info.properties.paged) && e->info.properties.block_idx<NUM_RAM_BLOCKS){
#ifdef VDM_DEBUG
			printf("(INFO)history_confirm: removing segment %u:%u \n",e->id.decoded.source_id, e->id.decoded.sequence_nr);
#endif
			//sd_block_t* block = &(vdm_buffer[e->info.properties.block_idx]);
			/*if(block->frames[e->info.properties.frame_idx].decoded.payload.seg.key.raw != e->id.raw)
				printf("history INDEX error b%u(%u) f%u content %u:%u!\n", 
					e->info.properties.block_idx, 
					block,
					e->info.properties.frame_idx, 
					block->frames[e->info.properties.frame_idx].decoded.payload.seg.key.decoded.source_id, 
					block->frames[e->info.properties.frame_idx].decoded.payload.seg.key.decoded.sequence_nr);*/

			vdm_remove_frame(e->info.properties.block_idx, e->info.properties.frame_idx);
			e->info.properties.block_idx = HISTORY_UNBUFFERED;

			return CONFIRMED;
		}
		//else
			//printf("not removing %u:%u paged %u, block idx %u \n",e->id.decoded.source_id, e->id.decoded.sequence_nr,!(e->info.properties.paged), e->info.properties.block_idx);
	}

	//search manually for locked packet in buffer but not in history
	uint8_t i, j;
	for(i=0; i < NUM_RAM_BLOCKS; i++){
		for(j=0; j < NUM_FRAMES; j++){
			if(vdm_buffer[i].frames[j].decoded.payload.seg.key.raw == id.raw){
				vdm_remove_frame(i,j);
#ifdef VDM_DEBUG
				printf("(INFO)history_confirm: removing segment not in history %u:%u \n",e->id.decoded.source_id, e->id.decoded.sequence_nr);
#endif
				return LOCKED;
			}
		}
	}

//#ifdef VDM_DEBUG
	printf("(INFO)history_confirm: segment unknown %u:%u\n",e->id.decoded.source_id, e->id.decoded.sequence_nr);
//#endif
	return UNKNOWN;
}

/**
 *  @return status of a history entry
 */
enum segment_status history_segmentState(segment_key_t id){
	history_entry_t* e= (history_entry_t*)&(history[HASH(id)]);
	if(e->id.raw == id.raw){
		if(e->info.properties.confirmed)
			return CONFIRMED;

		if(e->info.properties.paged)
			return UNCONFIRMED;

		return LOCKED;
	}

	return UNKNOWN;
}


